package com.autonavi.yunda.yunji.groovy.test

import com.alibaba.fastjson.JSONObject
import com.autonavi.yunda.yunji.common.utils.JsonUtils
import com.autonavi.yunda.yunji.core.engine.exception.EngineException
import com.autonavi.yunda.yunji.core.utils.diling.ObjectUtil
import org.apache.commons.collections.CollectionUtils
import org.apache.commons.lang3.StringUtils
import org.slf4j.Logger
import org.slf4j.LoggerFactory

import static java.util.stream.Collectors.toSet

/**
 * @author cizhong.wcs
 * @date 2023/7/27 19:57
 */
class ChargeCntUtilG {
    static Logger log = LoggerFactory.getLogger("ChargeCntUtilG")

    static void main(String[] args) {
        def strx = "[{\"uv\":187348,\"hour\":-1,\"hascar_dist\":\"0\\u0003138381\\u00021\\u000350269\\u0002-1\\u00030\",\"wkd_drive_dist\":\"1\\u000324572\\u00022\\u00035556\\u0002-1\\u0003159730\",\"high_hotel_dist\":\"1\\u000355731\\u0002-1\\u0003132958\"}]"
        println JsonUtils.from(strx, Object.class)
        def str = """[{"uv":187348,"hour":-1,"hascar_dist":"0\\u0003138381\\u00021\\u000350269\\u0002-1\\u00030","wkd_drive_dist":"1\\u000324572\\u00022\\u00035556\\u0002-1\\u0003159730","high_hotel_dist":"1\\u000355731\\u0002-1\\u0003132958"}]""".toString()
        println str
        println JsonUtils.from(str, Object.class)
        def str2 = """[{"uv":187348,"hour":-1,"hascar_dist":"0\u0003138381\u00021\u000350269\u0002-1\u00030","wkd_drive_dist":"1\u000324572\u00022\u00035556\u0002-1\u0003159730","high_hotel_dist":"1\u000355731\u0002-1\u0003132958"}]"""
        println str2
        println str2.replaceAll("\\\\", "\\\\\\\\").toString()
        println """["]\\""".replaceAll("\\\\", "\\\\\\\\")
        println JsonUtils.from(str2.replaceAll("\\\\", "\\\\\\\\").toString(), Object.class)

        def data = [
                "dataApiO"     : com.autonavi.yunda.yunji.core.engine.argresolver.ParamResolver.getParamValueByType(str2.toString().replaceAll("\\\\", "\\\\\\\\"), """object"""),
                "request"      : com.autonavi.yunda.yunji.core.engine.argresolver.ParamResolver.getParamValueByType("""{"profile":"offline_brand_dist,wkd_drive_dist,pmnt_city_dist,comptype_dist,hascar_dist,high_hotel_dist,pmnt_prov_dist"}""", """object"""),
                "chargeCntRule": com.autonavi.yunda.yunji.core.engine.argresolver.ParamResolver.getParamValueByType("""{"input":{"params":{"key":"profile2","function":"notNull_0"}},"output":{"params":{"key":"ds","function":"profileChargeCnt"}},"cal":{"operation":"max"}}""", """string"""),
        ]
        println getChargeCnt2(data.dataApiO, data.request, data.chargeCntRule)
    }

    static int getChargeCnt2(Object dataApiO, Map<String, String> request, String chargeCntRule) {
        int chargeCnt = 0;
        //计费逻辑
        boolean isListAndNotEmpty = true;
        if (dataApiO instanceof List) {
            if (CollectionUtils.isEmpty((List) dataApiO)) {
                isListAndNotEmpty = false;
            }
        }
        if (ObjectUtil.isNotEmpty(dataApiO) && isListAndNotEmpty) {
            chargeCnt = 1;
            //可转query结果可转json时判断data_size是否为0，为0不计费
            try {
                JSONObject jsonObject = (JSONObject) JSONObject.toJSON(dataApiO);
                if (jsonObject.containsKey("data_size") && Objects.nonNull(jsonObject.get("data_size"))) {
                    Integer resultSize = jsonObject.getInteger("data_size");
                    if (resultSize == 0) {
                        chargeCnt = 0;
                    }
                }
                if (jsonObject.containsKey("index") && Objects.nonNull(jsonObject.get("index"))) {
                    Integer resultSize = jsonObject.getInteger("index");
                    if (resultSize == 0) {
                        chargeCnt = 0;
                    }
                }
            } catch (Exception e) {
                //do nothing
            }
        }
        //todo 与原有逻辑有所不同，待确认
        if (dataApiO instanceof List) {
            if (((List) dataApiO).isEmpty()) {
                chargeCnt = 0;
            }
        }
        if (StringUtils.isNotBlank(chargeCntRule)) {
            chargeCnt = getChargeCnt(dataApiO, request, chargeCntRule);
        }
        return chargeCnt;
    }

    /**
     * 接口计费计费
     *
     * @param resObject 出参结果对象
     * @param request 入参参数列表
     * @param ruleString 计费规则
     * @return
     */
    public static int getChargeCnt(Object resObject, Map<String, String> request, String ruleString) {
        //查询结果
        List<Map<String, Object>> resJson;
        try {
            if (resObject instanceof List) {
                resJson = (List<Map<String, Object>>) resObject;
            } else if (resObject instanceof Map) {
                resJson = new ArrayList<>();
                resJson.add((JSONObject) resObject);
            } else if (resObject instanceof Number) {
                resJson = new ArrayList<>();
                Map<String, Object> stringObjectHashMap = new HashMap<>();
                stringObjectHashMap.put("number", resObject);
                resJson.add(stringObjectHashMap);
            } else {
                throw new EngineException("1103", "结果类型不符合计费类型，map，maplist，number等.");
            }
            JSONObject rules = JSONObject.parseObject(ruleString);
            //统计入参计次
            def inCnt = [cntNum: 0, cntSet: new HashSet<>(), profileSet: new HashSet<>()]
            JSONObject intput = rules.getJSONObject("input");
            JSONObject params = intput.getJSONObject("params");
            String key = params.getString("key");
            String operator = params.getString("function");
            String s = request.get(key);
            inCnt = parse(s, operator, inCnt, null, null);

            //统计结果计次
            def outCnt = [cntNum: 0, cntSet: new HashSet<>(), profileSet: new HashSet<>()];
            String outStr = "";
            JSONObject output = rules.getJSONObject("output");
            JSONObject result = output.getJSONObject("params");
            operator = result.getString("function");
            //计费若为根据是否非空判断时，不需要循环
            if (operator.startsWith("notNull_")) {
                parse(String.valueOf(resJson), operator, outCnt, null, null);
            } else {
                for (Map<String, Object> singleJsonObejct : resJson) {
                    outStr = String.valueOf(Optional.ofNullable(singleJsonObejct.get(result.getString("key"))).orElse(""));
                    outCnt = parse(outStr, operator, outCnt, singleJsonObejct, s);
                }
            }
            //计费算子
            String operation = rules.getJSONObject("cal").getString("operation");
            //计算最终结果
            return ChargeCntCal(operation, inCnt, outCnt);
        } catch (Exception e) {
            log.error("ChargeCntCal 计费运算错误 :", e.getMessage(), e);
        }
        return 0;
    }

    /**
     * 根据计费算子计算结果
     *
     * @param operation 计费算子
     * @param inCnt 入参计费变量
     * @param outCnt 出参计费变量
     * @return
     */
    private static int ChargeCntCal(String operation, def inCnt, def outCnt) {
        if ("*".equals(operation)) {
            return inCnt.cntNum * outCnt.cntNum;
        } else if ("+".equals(operation)) {
            return inCnt.cntNum + outCnt.cntNum;

        } else if ("min".equals(operation)) {
            return Math.min(inCnt.cntNum, outCnt.cntNum);
        } else if ("max".equals(operation)) {
            return Math.max(inCnt.cntNum, outCnt.cntNum);
        } else if ("intersection".equals(operation)) {
            //计算交集个数
            Set<String> interSet = new HashSet<>();
            interSet.addAll(inCnt.cntSet);
            interSet.retainAll(outCnt.cntSet);
            return interSet.size();
        } else if ("union".equals(operation)) {
            //计算并集个数
            Set<String> interSet = new HashSet<>();
            interSet.addAll(inCnt.cntSet);
            interSet.addAll(outCnt.cntSet);
            return interSet.size();
        }
        return 0;
    }

    /**
     * @param s 待统计内容
     * @param operator 统计算子
     * @param result 统计结果存储
     * @param singleJsonObejct getQueryResult算子直接取数所用的对象
     * @return
     */
    private static def parse(String s, String operator, def result, Map<String, Object> singleJsonObejct
                             , String inputParam) {
        if (StringUtils.isBlank(s) && !"profileChargeCnt".equals(operator)) {
            result.cntNum = (0);
        } else if ("split".equals(operator)) {
            result.cntNum = (s.split(",").length);

        } else if ("length".equals(operator)) {
            result.cntNum = (s.length());

        } else if ("distinct".equals(operator)) {
            //获取参数的去重结果和去重后的长度
            result.cntSet.addAll(Arrays.stream(s.split(",")).collect(toSet()));
            result.cntNum = (result.cntSet.size());
        } else if (operator.startsWith("notNull_")) {
            //对象不为空根据自定义的值计费
            if (StringUtils.isNotBlank(s)) {
                result.cntNum = (Integer.parseInt(operator.split("_")[1]));
            }
        } else if (operator.equals("getQueryResult")) {
            //直接获取查询结果作为计费项
            result.cntNum = (Integer.parseInt(singleJsonObejct.get("number").toString()));
        } else if ("profileChargeCnt".equals(operator)) {  //仅用于output处理
            Set<String> interSet = new HashSet<>();
            interSet.addAll(singleJsonObejct.keySet());
            //与入参指定字段计算交集
            if (StringUtils.isNotBlank(inputParam)) {
                interSet.retainAll(Arrays.stream(inputParam.split(",")).map(m -> m.trim()).collect(toSet()));
            }
            result.profileSet.addAll(interSet);
            //根据指定的去重字段进行计数，不传时计为1
            if (StringUtils.isNotBlank(s)) {
                result.cntSet.addAll(Arrays.stream(s.split(",")).collect(toSet()));
            }
            int cntDistinct = result.cntSet.size() == 0 ? 1 : result.cntSet.size();
            result.cntNum = (cntDistinct * result.profileSet.size());
        }
        return result;

    }
}